package lock

import (
	"runtime"
	"sync"
)

var objLock *ObjLock
var once sync.Once

const magicNum byte = 0

type ObjLock struct {
	mapGroup     []*sync.Map
	processorNum int
}

func InitObjLock() {
	once.Do(func() {
		processorNum := runtime.NumCPU()
		mapGroup := make([]*sync.Map, processorNum)
		for i := range mapGroup {
			mapGroup[i] = &sync.Map{}
		}
		objLock = &ObjLock{
			mapGroup:     mapGroup,
			processorNum: processorNum,
		}
	})
}

func GetObjLock() *ObjLock {
	if objLock == nil {
		panic("should init objLock first")
	}
	return objLock
}

func (o *ObjLock) TryLock(val *int32) bool {
	hash := int(*val) % o.processorNum
	targetMap := o.mapGroup[hash]
	_, exist := targetMap.LoadOrStore(val, magicNum)
	return !exist
}
